
#include "pl.h"

extern int n;/*o numero de vertices*/
extern int m;/*o numero de arestas*/
extern int k;/*o k da coloração*/
extern long va[];/*a ordem dos verties*/

long var[MAX_SIZE][MAX_SIZE];//mapeamento vertice ->variavel->vertice
long edges[MAX_SIZE][MAX_SIZE];//mapeamento vertice -> variavel
long varNum[MAX_SIZE];//numero de variaveis de cada vertice
int indice[MAX_SIZE];//vetor auxiliar usado pelas funções do cplex
int sink[MAX_SIZE];//se sink[i] = 0, i é um sumidouro e sink[i] = 1 em caso contrario

int initPL(){
	int i, j;
	//armazena os mapeamentos
	for(i = 0; i < n; i++){
		varNum[va[i]] = 0;
		indice[i] = i;
		for(j = i+1; j < n; j++){
			if(hasEdge(va[i], va[j])){
				var[va[i]][varNum[va[i]]] = va[j];
				edges[va[i]][va[j]] = varNum[va[i]];
				varNum[va[i]]++;
			}
		}
	}
	//determina os sumidouros
	for(i = 0; i < n; i++){
		if(varNum[va[i]] > 0) sink[va[i]] = 1;
		else sink[va[i]] = 0;
	}
	return 0;
}

int addEdgeConstrain(long v, long w, long u, CPXENVptr* env, CPXLPptr* prob){
	double rhs[1] = {1.0};//lado direito da restriçao
	char sense[1] = {'L'};// sentido da restriçao
	int rmatbeg[2] = {0,2};
	int rmatind[2];
	rmatind[0] = edges[va[v]][w];
	rmatind[1] = edges[va[v]][u];
	double rmatval[2] = {1.0, 1.0};
	int add = CPXaddrows(*env, *prob, 0, 1, 2, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	return add;
}

int addConstrainsForVertex(long v, CPXENVptr* env, CPXLPptr* prob){
	if(sink[va[v]] == 0) return 0;
	int status,i,j;
	*prob = CPXcreateprob(*env, &status, "problema");
	double obj[n];
	double lb[n];
	double ub[n];
	char type[n];
	for(i=0; i < n; i++){
		obj[i] = 1.0;
		lb[i] = 0.0;
		ub[i] = 1.0;
		type[i] = 'C';
	}
	//cria as variavies
	CPXnewcols(*env, *prob, varNum[va[v]], obj, lb, ub, type, NULL);
	//defini o sentindo da função objetivo
	CPXchgobjsen(*env, *prob, CPX_MAX);
	for(i = v+1; i < n; i++){
		if(hasEdge(va[i],va[v])){
			for(j = i+1; j < n ; j++){
				if(hasEdge(va[j],va[v]) && (!hasEdge(va[j],va[i]))){
					addEdgeConstrain(v, va[i], va[j], env, prob);
				}
			}
		}
	}
	//defini o tipo do problema
	CPXchgprobtype(*env, *prob, CPXPROB_LP);
	return 0;
}

double solve(CPXENVptr env, CPXLPptr prob, long v){
	if(sink[va[v]] == 0){
		return 0;
	}
	int status = CPXlpopt(env, prob);
	getErro(status);
	double value;
	CPXgetobjval(env,prob, &value);
	return value;
}

int getX(CPXENVptr env, CPXLPptr prob, double* x, long v){
	if(sink[va[v]] == 0){
		int i;
		for(i = 0; i < n; i++){
			x[i] = 0.0;
		}
		x[va[v]] = 1.0;
		return 0;
	}
	double y[n];
	int i;
	int status = CPXgetx (env, prob, y, 0, varNum[va[v]]-1);
	getErro(status);
	for(i = 0; i < n; i++){
		x[i] = 0.0;
	}
	for(i = 0; i < varNum[va[v]]; i++){
		x[var[va[v]][i]] = y[i];
	}
	x[va[v]] = 1.0;
	return status;
}

int changeObj(CPXENVptr env, CPXLPptr prob, double* coef, long v){
	if(sink[va[v]] == 0) return 0;
	int status = CPXchgobj(env, prob, varNum[va[v]], indice, coef);
	getErro(status);
	return status;
}

int getErro(int st){
	if(st != 0){
		char buffer[100];
		CPXgeterrorstring (env, status, buffer);
		printf ("%s \n", buffer);
	}
	return st;
}
